﻿using SuperX.Common.Collection;
using SuperX.Common;
using System;
using System.Collections.Generic;
using System.Text;
using SuperX.DataService.Abstract;
using Newtonsoft.Json;
using System.Linq;
using System.Threading;
using SuperX.Common.Log;
using System.Runtime.InteropServices;

namespace SuperX.DataService
{
    public abstract class BaseDeviceGroup : BasicObjCollection<IBasicObject>
    {
        protected ObjectCollection<BaseDeviceGroup, IIOTag> _IOTagGroup;

        public ObjectCollection<BaseDeviceGroup, IIOTag> IOTagGroup
        {
            get => _IOTagGroup ?? (_IOTagGroup = new ObjectCollection<BaseDeviceGroup, IIOTag>(this));
            set
            {
                _IOTagGroup = value;
                _IOTagGroup.SetParent(this);
            }
        }

        protected List<IIOTag> _items;

        public IEnumerable<IIOTag> Items
        {
            get { return _IOTagGroup.Values; }
        }

        protected IDataServer _server;

        [JsonIgnore]
        public IDataServer Server
        {
            get
            {
                return _server;
            }
        }

        protected short _id;

        public short ID
        {
            get
            {
                return _id;
            }
        }

        public override IBasicObject this[string name] => IOTagGroup[name];

        public string ConfigName { get; set; }

        //可采用定期轮询和消息通知改变两种方式
        protected bool _isActive;

        private Thread _thread;

        private bool IsRunning;

        public virtual bool IsActive
        {
            get
            {
                return _isActive;
            }
            set
            {
                _isActive = value;
                if (value)
                {
                    if (_updateRate <= 0) _updateRate = 100;
                    IsRunning = true;
                    _thread = new Thread(OnUpdate) { IsBackground = true };
                    _thread.Start();
                }
                else
                {
                    IsRunning = false;
                    _thread?.Abort();
                }
            }
        }

        private void OnUpdate()
        {
            while (true)
            {
                Thread.Sleep(_updateRate);
                lock (this)
                {
                    if (!_isActive)
                    {
                        return;
                    }
                    try
                    {
                        Update();
                    }
                    catch (Exception ex)
                    {
                        Logger.Warn($"{this.FullName} update error{ex.Message}");
                    }
                }
            }
        }

        public virtual void Update()
        {
        }

        protected int _updateRate;

        public int UpdateRate
        {
            get
            {
                return _updateRate;
            }
            set
            {
                _updateRate = value;
            }
        }

        private float deadband;

        public float DeadBand
        {
            get
            {
                return deadband;
            }
            set
            {
                deadband = value;
            }
        }

        public bool SetActiveState(bool active, params long[] items)
        {
            return true;
        }

        public override void Dispose()
        {
            _IOTagGroup = null;
            _thread?.Abort();
            base.Dispose();
        }

        public override List<string> GetKeys()
        {
            return IOTagGroup.Keys.ToList();
        }

        public override List<IBasicObject> GetValues()
        {
            var tags = IOTagGroup.Values.OfType<IBasicObject>().ToList();
            return tags;
        }

        public override bool IsUniqueName(string name, IObjCollection parent)
        {
            if (parent != null)
            {
                return parent.IsUniqueName(name, null);
            }

            return IOTagGroup[name] == null;
        }

        public bool AddTags(IEnumerable<IIOTag> tags)
        {
            foreach (IIOTag tag in tags)
            {
                if (tag != null)
                {
                    IOTagGroup.Add(tag);
                }
            }
            return true;
        }

        public bool RemoveItems(params IIOTag[] items)
        {
            foreach (var item in items)
            {
                _server.RemoveItemIndex(item.Name);
                IOTagGroup.Remove(item);
            }
            return true;
        }

        public IIOTag FindItemByAddress(DeviceAddress addr)
        {
            int id = addr.CacheIndex;
            if (IOTagGroup[addr.Name] != null) return IOTagGroup[addr.Name];
            return null;
        }
    }
}